import shlex
import subprocess
from pathlib import Path
from platform import system
from shutil import which

from typing import List

import psutil

from src.custom.function import check_process_type

class FFMPEG:
    def __init__(self, path: str):
        self.processes = []
        self.path = self.__check_ffmpeg_path(Path(path))
        self.state = bool(self.path)
        self.command, self.shell = self._check_system_type()

    @staticmethod
    def _check_system_type():
        if (s := system())=="Darwin":  # macOS
            return ['open', '-a', 'Terminal'], False
        elif s=="Windows":  # Windows
            return ['start', 'cmd', '/k'], True
        elif s=="Linux":  # Linux
            return [], False

    def __check_ffmpeg_path(self, path: Path):
        # return None  # 调试使用
        state = self.__check_system_ffmpeg() or self.__check_system_ffmpeg(path)
        if state:
            return path
        return "ffmpeg" if subprocess.run(["ffmpeg",
                                           "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) else None

    def download(self, data: List[tuple], proxies, timeout, user_agent):
        processIds = []
        for u, p in data:
            command = self.__generate_command(
                u, p, proxies, timeout, user_agent)
            if self.shell:
                process = subprocess.Popen(command, shell=self.shell)
            else:
                process = subprocess.Popen(shlex.split(command))
            self.processes.append(process)
            # Get and print the process ID
            # print("Process ID:", process.pid)
            processIds.append(process.pid)
        return processIds

    def stop_process(self, process_id):
        for process in self.processes:
            if process.pid==process_id:
                process.terminate()
                return {"process_id": process_id, "result": "success"}
        if check_process_type(process_id, "ffmpeg"):
            try:
                process = psutil.Process(process_id)
                process.terminate()
                print(f"Process with PID {process_id} terminated")
                results = {"process_id": process_id, "result": "success"}
            except psutil.NoSuchProcess as e:
                results = {"process_id": process_id, "result": f"Process with PID {process_id} not found."}
        else:
            results = {"process_id": process_id, "result": "Process with PID {process_id} not found."}
        return results


    def __generate_command(
            self,
            url,
            file,
            proxies,
            timeout,
            user_agent) -> str:
        command = self.command.copy()
        command.extend([
            self.path,
            "-hide_banner",
            "-protocol_whitelist", "rtmp,crypto,file,http,https,tcp,tls,udp,rtp",
            "-fflags", "+discardcorrupt",
            "-timeout", f"{timeout * 1000 * 1000}",
            "-user_agent", f'"{user_agent}"',
            "-i", f'"{url}"',
            "-bufsize", "5120k",
            "-map", "0",
            "-c:v", "copy",
            "-c:a", "copy",
            "-sn", "-dn",
            "-reconnect_delay_max", "15",
            "-reconnect_streamed", "-reconnect_at_eof",
            "-max_muxing_queue_size", "64",
            "-correct_ts_overflow", "1",
        ])

        system_type = system()
        if system_type=="Windows":
            command.extend(["-log_level", "error"])  # Windows 版本使用 -log_level 选项
        else:
            command.extend(["-loglevel", "error"])  # macOS 版本使用 -loglevel 选项
        if proxies:
            for insert_index, item in enumerate(
                    ("-http_proxy", proxies), start=len(self.command) + 2):
                command.insert(insert_index, item)

        command = ["" if item is None else item for item in command]
        command.append(f'"{file}"')
        # print(" ".join(command))
        return " ".join(command)

    @staticmethod
    def __check_system_ffmpeg(path: Path = None):
        return which(str(path) or "ffmpeg")
